﻿using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using iWare.Wms.Core;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Linq.Dynamic.Core;

namespace iWare.Wms.Application
{
    /// <summary>
    /// 分拣管理服务
    /// </summary>
    [Route("api/WareSortOrder")]
    [ApiDescriptionSettings("分拣管理", Name = "WareSortOrder", Order = 100)]

    public class WareSortOrderService : IDynamicApiController, ITransient
    {
        private readonly IRepository<WareContainer, MasterDbContextLocator> _wareContainerRep; //容器仓储
        private readonly IRepository<WareContainerVsMaterial, MasterDbContextLocator> _wareContainerVsMaterialRep; //容器与物料关系仓储
        private readonly IRepository<WareStock, MasterDbContextLocator> _wareStockRep; //库存仓储
        private readonly IRepository<WareSortOrder, MasterDbContextLocator> _wareSortOrderRep; //分开仓储
        private readonly IRepository<WareOrderDetails, MasterDbContextLocator> _wareOrderDetailsRep; //单据明细仓储

        #region 默认
        /// <summary>
        /// 默认
        /// </summary>
        /// <param name="wareContainerRep"></param>
        /// <param name="wareContainerVsMaterialRep"></param>
        /// <param name="wareStockRep"></param>
        /// <param name="wareSortOrderRep"></param>
        /// <param name="wareOrderDetailsRep"></param>
        public WareSortOrderService(
            IRepository<WareContainer, MasterDbContextLocator> wareContainerRep,
            IRepository<WareContainerVsMaterial, MasterDbContextLocator> wareContainerVsMaterialRep,
            IRepository<WareStock, MasterDbContextLocator> wareStockRep,
            IRepository<WareSortOrder, MasterDbContextLocator> wareSortOrderRep,
            IRepository<WareOrderDetails, MasterDbContextLocator> wareOrderDetailsRep
        )
        {
            _wareContainerRep = wareContainerRep;
            _wareContainerVsMaterialRep = wareContainerVsMaterialRep;
            _wareStockRep = wareStockRep;
            _wareSortOrderRep = wareSortOrderRep;
            _wareOrderDetailsRep = wareOrderDetailsRep;
        }
        #endregion

        /// <summary>
        /// 分页查询分拣信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("page")]
        public async Task<PageResult<WareSortOrderOutput>> Page([FromQuery] WareSortOrderSearch input)
        {
            return await _wareSortOrderRep.DetachedEntities
                .Where(input.SortStatus != SortStatusEnum.All, u => u.SortStatus == input.SortStatus)
                .Where(!string.IsNullOrEmpty(input.OrderNo), u => EF.Functions.Like(u.OrderNo, $"%{input.OrderNo.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.ContainerOrderNo), u => EF.Functions.Like(u.ContainerOrderNo, $"%{input.ContainerOrderNo.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.ProjectCode), u => EF.Functions.Like(u.ProjectCode, $"%{input.ProjectCode.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.ContainerCode), u => EF.Functions.Like(u.ContainerCode, $"%{input.ContainerCode.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.Code), u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.CreatedUserName), u => EF.Functions.Like(u.CreatedUserName, $"%{input.CreatedUserName.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.SearchBeginTime), u => u.CreatedTime >= DateTime.Parse(input.SearchBeginTime.Trim()) &&
                 u.CreatedTime <= DateTime.Parse(input.SearchEndTime.Trim()))
                .OrderBy(u => u.SortStatus)
                .ThenByDescending(u => u.CreatedTime)
                .ThenByDescending(u => u.UpdatedTime)
                .ProjectToType<WareSortOrderOutput>()
                .ToADPagedListAsync(input.PageNo, input.PageSize);
        }

        /// <summary>
        /// 强制分拣完成
        /// </summary>
        /// <returns></returns>
        [HttpPost("SortOrderFinish")]
        [UnitOfWork]
        public async Task SortOrderFinish([FromBody] SortOrderFinishInput input)
        {
            if (input == null) throw Oops.Oh("传递参数异常!");

            //检查托盘
            var wareContainer = await _wareContainerRep.FirstOrDefaultAsync(z => z.Code == input.ContainerCode);
            if (wareContainer == null) throw Oops.Oh("容器信息不存在!");
            if (wareContainer.ContainerStatus == ContainerStatusEnum.jinyong) throw Oops.Oh("容器已禁用!");
            if (wareContainer.ContainerStatus == ContainerStatusEnum.kuwei) throw Oops.Oh("容器在库位不可使用!");
            if (wareContainer.ContainerStatus != ContainerStatusEnum.fenjian) throw Oops.Oh("容器不存在分拣信息!");

            // 查询容器与物料关系状态为正常的
            var WareContainerVsMaterials = await _wareContainerVsMaterialRep.DetachedEntities
               .Where(p => p.WareContainer.Code == input.ContainerCode && p.ContainerVsMaterialStatus == CommonStatus.ENABLE).ToListAsync();
            // 更新容器与物料的组盘数量
            var containerVsMaterialModel = WareContainerVsMaterials.FirstOrDefault(p => p.Code == input.Code && p.ProjectCode == input.ProjectCode);
            if (containerVsMaterialModel != null)
            {
                if (containerVsMaterialModel.BindQuantity < input.LocalQuantity) throw Oops.Oh("分拣组盘异常!");
                containerVsMaterialModel.BindQuantity -= input.LocalQuantity;
                await _wareContainerVsMaterialRep.UpdateAsync(containerVsMaterialModel);
            }

            // 更新库存
            var SortOrderModel = await _wareStockRep.FirstOrDefaultAsync(p => p.ContainerCode == wareContainer.Code
            && p.Code == input.Code&& p.ProjectCode == input.ProjectCode);
            if (SortOrderModel != null)
            {
                if (SortOrderModel.StockQuantity < input.LocalQuantity) throw Oops.Oh("分拣库存异常!");
                SortOrderModel.StockQuantity -= input.LocalQuantity;
                await _wareStockRep.UpdateAsync(SortOrderModel);
            }
            if (containerVsMaterialModel != null && SortOrderModel != null)
            {
                // 更新分拣状态
                var wareSortOrder = await _wareSortOrderRep.FirstOrDefaultAsync(p => p.Id == input.Id && p.ContainerCode == input.ContainerCode && p.ContainerOrderNo == input.ContainerOrderNo
                && p.ProjectCode == input.ProjectCode && p.Code == input.Code);

                if ((wareSortOrder.ActualQuantity + input.LocalQuantity) == wareSortOrder.SortQuantity)
                {
                    wareSortOrder.SortStatus = SortStatusEnum.Completed;
                    wareSortOrder.ActualQuantity += input.LocalQuantity;
                    _wareSortOrderRep.UpdateNow(wareSortOrder);
                }
                else
                {
                    wareSortOrder.SortStatus = SortStatusEnum.Sorting;
                    wareSortOrder.ActualQuantity += input.LocalQuantity;
                    _wareSortOrderRep.UpdateNow(wareSortOrder);
                }
            }

            // 分拣数量
            var wareSortOrderCount = await _wareSortOrderRep.DetachedEntities
               .Where(p => p.ContainerCode == input.ContainerCode && p.SortStatus != SortStatusEnum.Completed).CountAsync();

            //更新托盘状态，分拣完成
            if (wareSortOrderCount == 0)
            {
                if (WareContainerVsMaterials.Sum(t => t.BindQuantity) == 0) wareContainer.ContainerStatus = ContainerStatusEnum.kongxian;
                else wareContainer.ContainerStatus = ContainerStatusEnum.zupan;
                // 更新容器状态
                await _wareContainerRep.UpdateAsync(wareContainer);

                var OutWareContainerVsMaterials = await _wareContainerVsMaterialRep
                .Where(p => p.WareContainer.Code == input.ContainerCode && p.ContainerVsMaterialStatus == CommonStatus.DISABLE).ToListAsync();

                foreach (var itemModel in OutWareContainerVsMaterials)
                {
                    itemModel.ContainerVsMaterialStatus = CommonStatus.DELETED;
                    await _wareContainerVsMaterialRep.UpdateAsync(itemModel);
                }
            }
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <returns></returns>
        [HttpPost("Delete")]
        [UnitOfWork]
        public async Task Delete([FromBody] DeleteWareSortOrderInput input)
        {
            var sortOrder = await _wareSortOrderRep.FirstOrDefaultAsync(z => z.Id == input.Id);
            if (sortOrder == null) throw Oops.Oh("数据不存在");

            // 还原当前库存数量
            var stock = await _wareStockRep.FirstOrDefaultAsync(z => z.ContainerCode == sortOrder.ContainerCode
            && z.ProjectCode == sortOrder.ProjectCode && z.Code == sortOrder.Code && z.SpecificationModel == sortOrder.SpecificationModel);
            stock.CurrentQuantity += sortOrder.SortQuantity;
            await _wareStockRep.UpdateAsync(stock);

            //还原单据明细分拣数
            var orderDetail = await _wareOrderDetailsRep.FirstOrDefaultAsync(z => z.ContainerCode == sortOrder.ContainerCode
            && z.ProjectCode == sortOrder.ProjectCode && z.Code == sortOrder.Code && z.Id == sortOrder.OrderDetailID);
            orderDetail.ActualQuantity -= sortOrder.SortQuantity;

            // 删除分拣信息
            await _wareSortOrderRep.DeleteAsync(sortOrder);
        }
    }
}
